#include "U2DefaultHardwareBufferManager.h"

#include "U2Exception.h"
#include "U2MemoryAllocatorConfig.h"


U2EG_NAMESPACE_USING


U2DefaultHardwareVertexBuffer::U2DefaultHardwareVertexBuffer(size_t vertexSize, size_t numVertices, 
														 U2HardwareBuffer::Usage usage)
: U2HardwareVertexBuffer(0, vertexSize, numVertices, usage, true, false) // always software, never shadowed
{
    // Allocate aligned memory for better SIMD processing friendly.
    mpData = static_cast<unsigned char*>(U2_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
}
//-----------------------------------------------------------------------
U2DefaultHardwareVertexBuffer::U2DefaultHardwareVertexBuffer(U2HardwareBufferManagerBase* mgr, size_t vertexSize, size_t numVertices, 
	U2HardwareBuffer::Usage usage)
    : U2HardwareVertexBuffer(mgr, vertexSize, numVertices, usage, true, false) // always software, never shadowed
{
    // Allocate aligned memory for better SIMD processing friendly.
    mpData = static_cast<unsigned char*>(U2_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
}
//-----------------------------------------------------------------------
U2DefaultHardwareVertexBuffer::~U2DefaultHardwareVertexBuffer()
{
	U2_FREE_SIMD(mpData, MEMCATEGORY_GEOMETRY);
}
//-----------------------------------------------------------------------
void* U2DefaultHardwareVertexBuffer::lockImpl(size_t offset, size_t length, LockOptions options)
{
    // Only for use internally, no 'locking' as such
	return mpData + offset;
}
//-----------------------------------------------------------------------
void U2DefaultHardwareVertexBuffer::unlockImpl(void)
{
    // Nothing to do
}
//-----------------------------------------------------------------------
void* U2DefaultHardwareVertexBuffer::lock(size_t offset, size_t length, LockOptions options)
{
    mIsLocked = true;
	return mpData + offset;
}
//-----------------------------------------------------------------------
void U2DefaultHardwareVertexBuffer::unlock(void)
{
    mIsLocked = false;
    // Nothing to do
}
//-----------------------------------------------------------------------
void U2DefaultHardwareVertexBuffer::readData(size_t offset, size_t length, void* pDest)
{
	assert((offset + length) <= mSizeInBytes);
	memcpy(pDest, mpData + offset, length);
}
//-----------------------------------------------------------------------
void U2DefaultHardwareVertexBuffer::writeData(size_t offset, size_t length, const void* pSource,
		bool discardWholeBuffer)
{
	assert((offset + length) <= mSizeInBytes);
	// ignore discard, memory is not guaranteed to be zeroised
	memcpy(mpData + offset, pSource, length);

}
//-----------------------------------------------------------------------

U2DefaultHardwareIndexBuffer::U2DefaultHardwareIndexBuffer(IndexType idxType, 
	size_t numIndexes, U2HardwareBuffer::Usage usage) 
	: U2HardwareIndexBuffer(0, idxType, numIndexes, usage, true, false) // always software, never shadowed
{
	mpData = U2_ALLOC_T(unsigned char, mSizeInBytes, MEMCATEGORY_GEOMETRY);
}
//-----------------------------------------------------------------------
U2DefaultHardwareIndexBuffer::~U2DefaultHardwareIndexBuffer()
{
	U2_FREE(mpData, MEMCATEGORY_GEOMETRY);
}
//-----------------------------------------------------------------------
void* U2DefaultHardwareIndexBuffer::lockImpl(size_t offset, size_t length, LockOptions options)
{
    // Only for use internally, no 'locking' as such
	return mpData + offset;
}
//-----------------------------------------------------------------------
void U2DefaultHardwareIndexBuffer::unlockImpl(void)
{
    // Nothing to do
}
//-----------------------------------------------------------------------
void* U2DefaultHardwareIndexBuffer::lock(size_t offset, size_t length, LockOptions options)
{
    mIsLocked = true;
	return mpData + offset;
}
//-----------------------------------------------------------------------
void U2DefaultHardwareIndexBuffer::unlock(void)
{
    mIsLocked = false;
    // Nothing to do
}
//-----------------------------------------------------------------------
void U2DefaultHardwareIndexBuffer::readData(size_t offset, size_t length, void* pDest)
{
	assert((offset + length) <= mSizeInBytes);
	memcpy(pDest, mpData + offset, length);
}
//-----------------------------------------------------------------------
void U2DefaultHardwareIndexBuffer::writeData(size_t offset, size_t length, const void* pSource,
		bool discardWholeBuffer)
{
	assert((offset + length) <= mSizeInBytes);
	// ignore discard, memory is not guaranteed to be zeroised
	memcpy(mpData + offset, pSource, length);

}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
U2DefaultHardwareBufferManagerBase::U2DefaultHardwareBufferManagerBase()
{
}
//-----------------------------------------------------------------------
U2DefaultHardwareBufferManagerBase::~U2DefaultHardwareBufferManagerBase()
{
    destroyAllDeclarations();
    destroyAllBindings(); 
}
//-----------------------------------------------------------------------
U2HardwareVertexBufferSharedPtr 
    U2DefaultHardwareBufferManagerBase::createVertexBuffer(size_t vertexSize, 
	size_t numVerts, U2HardwareBuffer::Usage usage, bool useShadowBuffer)
{
    U2DefaultHardwareVertexBuffer* vb = U2_NEW U2DefaultHardwareVertexBuffer(this, vertexSize, numVerts, usage);
    return U2HardwareVertexBufferSharedPtr(vb);
}
//-----------------------------------------------------------------------
U2HardwareIndexBufferSharedPtr 
    U2DefaultHardwareBufferManagerBase::createIndexBuffer(U2HardwareIndexBuffer::IndexType itype, 
	size_t numIndexes, U2HardwareBuffer::Usage usage, bool useShadowBuffer)
{
    U2DefaultHardwareIndexBuffer* ib = U2_NEW U2DefaultHardwareIndexBuffer(itype, numIndexes, usage);
	return U2HardwareIndexBufferSharedPtr(ib);
}
